From ff1e1e1f9123c69ca2ee733d0c674ba9faa14eaa Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 12 Jan 2012 02:34:27 +0100 Subject: [PATCH] a11y: Disconnect from buffer signals This way, we don't get crashes when the buffer is still in use after a TextView gets finalized. https://bugzilla.gnome.org/show_bug.cgi?id=667632 --- gtk/a11y/gtktextviewaccessible.c | 94 +++++++++++++++++++++----------- gtk/a11y/gtktextviewaccessible.h | 6 +- gtk/gtktextview.c | 7 ++- 3 files changed, 72 insertions(+), 35 deletions(-) diff --git a/gtk/a11y/gtktextviewaccessible.c b/gtk/a11y/gtktextviewaccessible.c index 97db302364..52e73ed670 100644 --- a/gtk/a11y/gtktextviewaccessible.c +++ b/gtk/a11y/gtktextviewaccessible.c @@ -31,9 +31,9 @@ #include #include #include "gtktextviewaccessible.h" +#include "gtk/gtkwidgetprivate.h" -static void setup_buffer (GtkTextView *view,GtkTextViewAccessible *accessible); static void insert_text_cb (GtkTextBuffer *buffer, GtkTextIter *arg1, gchar *arg2, @@ -65,8 +65,6 @@ gtk_text_view_accessible_initialize (AtkObject *obj, { ATK_OBJECT_CLASS (_gtk_text_view_accessible_parent_class)->initialize (obj, data); - setup_buffer (GTK_TEXT_VIEW (data), GTK_TEXT_VIEW_ACCESSIBLE (obj)); - obj->role = ATK_ROLE_TEXT; } @@ -85,10 +83,6 @@ gtk_text_view_accessible_notify_gtk (GObject *obj, editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (obj)); atk_object_notify_state_change (atk_obj, ATK_STATE_EDITABLE, editable); } - else if (!strcmp (pspec->name, "buffer")) - { - setup_buffer (GTK_TEXT_VIEW (obj), GTK_TEXT_VIEW_ACCESSIBLE (atk_obj)); - } else GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_text_view_accessible_parent_class)->notify_gtk (obj, pspec); } @@ -112,12 +106,50 @@ gtk_text_view_accessible_ref_state_set (AtkObject *accessible) return state_set; } +static void +gtk_text_view_accessible_change_buffer (GtkTextViewAccessible *accessible, + GtkTextBuffer *old_buffer, + GtkTextBuffer *new_buffer) +{ + if (old_buffer) + { + g_signal_handlers_disconnect_matched (old_buffer, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, accessible); + } + + if (new_buffer) + { + g_signal_connect_after (new_buffer, "insert-text", G_CALLBACK (insert_text_cb), accessible); + g_signal_connect (new_buffer, "delete-range", G_CALLBACK (delete_range_cb), accessible); + g_signal_connect_after (new_buffer, "mark-set", G_CALLBACK (mark_set_cb), accessible); + } +} + +static void +gtk_text_view_accessible_widget_set (GtkAccessible *accessible) +{ + gtk_text_view_accessible_change_buffer (GTK_TEXT_VIEW_ACCESSIBLE (accessible), + NULL, + gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_accessible_get_widget (accessible)))); +} + +static void +gtk_text_view_accessible_widget_unset (GtkAccessible *accessible) +{ + gtk_text_view_accessible_change_buffer (GTK_TEXT_VIEW_ACCESSIBLE (accessible), + gtk_text_view_get_buffer (GTK_TEXT_VIEW (gtk_accessible_get_widget (accessible))), + NULL); +} + static void _gtk_text_view_accessible_class_init (GtkTextViewAccessibleClass *klass) { AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + GtkAccessibleClass *accessible_class = GTK_ACCESSIBLE_CLASS (klass); GtkWidgetAccessibleClass *widget_class = (GtkWidgetAccessibleClass*)klass; + accessible_class->widget_set = gtk_text_view_accessible_widget_set; + accessible_class->widget_unset = gtk_text_view_accessible_widget_unset; + class->ref_state_set = gtk_text_view_accessible_ref_state_set; class->initialize = gtk_text_view_accessible_initialize; @@ -129,20 +161,6 @@ _gtk_text_view_accessible_init (GtkTextViewAccessible *accessible) { } -static void -setup_buffer (GtkTextView *view, - GtkTextViewAccessible *accessible) -{ - GtkTextBuffer *buffer; - - buffer = gtk_text_view_get_buffer (view); - - /* Set up signal callbacks */ - g_signal_connect_after (buffer, "insert-text", G_CALLBACK (insert_text_cb), view); - g_signal_connect (buffer, "delete-range", G_CALLBACK (delete_range_cb), view); - g_signal_connect_after (buffer, "mark-set", G_CALLBACK (mark_set_cb), view); -} - static gchar * gtk_text_view_accessible_get_text (AtkText *text, gint start_offset, @@ -1727,13 +1745,10 @@ insert_text_cb (GtkTextBuffer *buffer, gint len, gpointer data) { - GtkTextView *view = data; - GtkTextViewAccessible *accessible; + GtkTextViewAccessible *accessible = data; gint position; gint length; - accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view))); - position = gtk_text_iter_get_offset (iter); length = g_utf8_strlen (text, len); @@ -1748,12 +1763,9 @@ delete_range_cb (GtkTextBuffer *buffer, GtkTextIter *end, gpointer data) { - GtkTextView *view = data; - GtkTextViewAccessible *accessible; + GtkTextViewAccessible *accessible = data; gint offset, length; - accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (view))); - offset = gtk_text_iter_get_offset (start); length = gtk_text_iter_get_offset (end) - offset; @@ -1771,10 +1783,7 @@ mark_set_cb (GtkTextBuffer *buffer, GtkTextMark *mark, gpointer data) { - GtkTextView *text = data; - GtkTextViewAccessible *accessible; - - accessible = GTK_TEXT_VIEW_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (text))); + GtkTextViewAccessible *accessible = data; /* * Only generate the signal for the "insert" mark, which @@ -1929,3 +1938,22 @@ atk_streamable_content_interface_init (AtkStreamableContentIface *iface) iface->get_mime_type = gail_streamable_content_get_mime_type; iface->get_stream = gail_streamable_content_get_stream; } + +void +_gtk_text_view_accessible_set_buffer (GtkTextView *textview, + GtkTextBuffer *old_buffer) +{ + GtkTextViewAccessible *accessible; + + g_return_if_fail (GTK_IS_TEXT_VIEW (textview)); + g_return_if_fail (old_buffer == NULL || GTK_IS_TEXT_BUFFER (old_buffer)); + + accessible = GTK_TEXT_VIEW_ACCESSIBLE (_gtk_widget_peek_accessible (GTK_WIDGET (textview))); + if (accessible == NULL) + return; + + gtk_text_view_accessible_change_buffer (accessible, + old_buffer, + gtk_text_view_get_buffer (textview)); +} + diff --git a/gtk/a11y/gtktextviewaccessible.h b/gtk/a11y/gtktextviewaccessible.h index aacbaa3e18..3a049ee781 100644 --- a/gtk/a11y/gtktextviewaccessible.h +++ b/gtk/a11y/gtktextviewaccessible.h @@ -47,7 +47,11 @@ struct _GtkTextViewAccessibleClass GtkContainerAccessibleClass parent_class; }; -GType _gtk_text_view_accessible_get_type (void); +GType _gtk_text_view_accessible_get_type (void); + +void _gtk_text_view_accessible_set_buffer (GtkTextView *textview, + GtkTextBuffer *old_buffer); + G_END_DECLS diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index a048bc9c4d..95e63a7bdb 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -1479,6 +1479,7 @@ gtk_text_view_set_buffer (GtkTextView *text_view, GtkTextBuffer *buffer) { GtkTextViewPrivate *priv; + GtkTextBuffer *old_buffer; g_return_if_fail (GTK_IS_TEXT_VIEW (text_view)); g_return_if_fail (buffer == NULL || GTK_IS_TEXT_BUFFER (buffer)); @@ -1488,6 +1489,7 @@ gtk_text_view_set_buffer (GtkTextView *text_view, if (priv->buffer == buffer) return; + old_buffer = priv->buffer; if (priv->buffer != NULL) { /* Destroy all anchored children */ @@ -1531,7 +1533,6 @@ gtk_text_view_set_buffer (GtkTextView *text_view, if (priv->layout) gtk_text_layout_set_buffer (priv->layout, NULL); - g_object_unref (priv->buffer); priv->dnd_mark = NULL; priv->first_para_mark = NULL; cancel_pending_scroll (text_view); @@ -1581,6 +1582,10 @@ gtk_text_view_set_buffer (GtkTextView *text_view, } } + _gtk_text_view_accessible_set_buffer (text_view, old_buffer); + if (old_buffer) + g_object_unref (old_buffer); + g_object_notify (G_OBJECT (text_view), "buffer"); if (gtk_widget_get_visible (GTK_WIDGET (text_view))) -- 2.30.2